package com.example.controller;

import com.example.entity.SysUser;
import com.example.service.SysUserService;
import com.example.util.JwtUtil;
import com.example.util.R;
import com.example.util.RsaUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpSession;
import java.util.Date;
import java.util.Objects;

/**
 * ----MaxCV工程师---
 *
 * @author wangbiao，闫瑞华
 * @date2024/12/2
 * @desc
 */
@Slf4j
@RestController
@RequestMapping("/sys/user")
public class SysUserController {

    @Autowired
    private SysUserService sysUserService;
    @Autowired
    private JwtUtil jwtUtil;
    // 因 前端使用的名称就是 token，所以后端返回给前端的 短token 不能使用 shortToken 这个名称，否则前端无法接收到数据
    private String token;
    private String longToken;

    /**
     * 用户登录
     * @param sysUser
     * @param session
     * @return 返回 短token
     */
    @PostMapping("/login")
    public R login(@RequestBody SysUser sysUser, HttpSession session) throws Exception {
        // 执行登录前 先尝试从 session 中获取用户信息，用于判断 是否已经登录
        SysUser sessionUser = (SysUser) session.getAttribute("sysUser");
        if (sessionUser != null
                && !sysUser.getUserName().equals(sessionUser.getUserName())
                && !sysUser.getUserPassword().equals(sessionUser.getUserPassword())) {
            return R.fail("当前用户已登录，请勿重复登录！");
        }
        // 解密前端传入的密码
        sysUser.setUserPassword(RsaUtils.decryptByPrivateKey(sysUser.getUserPassword()));
        // 执行登录
        SysUser user =  sysUserService.login(sysUser);
        if (user == null){
            return R.fail("用户名或密码错误！");
        }
        // 生成 长短token，短token 返回给前端，并将 用户信息 保存在 session 中
        token = jwtUtil.generateShortToken(user);
        longToken = jwtUtil.generateLongToken(user);
        session.setAttribute("sysUser",user);
        return R.ok("登录成功！").put("token", token);
    }

    /**
     * 根据 token 获取登录用户信息
     * @param token 短token
     * @param session
     * @return 返回 用户信息 和 短token
     */
    @GetMapping("/info")
    public R info(String token ,HttpSession session) {
        SysUser sysUser = (SysUser) session.getAttribute("sysUser");
        // 先校验传入的 token 是否有内容，以及 session 中是否有用户信息
        if (token == null || token.equals("") || sysUser == null){
            return R.fail("登录已过期，请重新登录！");
        }
        // 然后校验 长短token 是否都过期
        else if (!jwtUtil.validateToken(token) && !jwtUtil.validateToken(longToken)) {
            return R.fail("登录已过期，请重新登录!");
        }
        // 最后校验是否为当前登录用户
        else if (Objects.equals(jwtUtil.getUserIdAsInteger(token), sysUser.getUserId())) {
            // 只有 短token 过期，则根据 长token 更新 短token，同时更新 长token
            if (jwtUtil.validateToken(token)) {
                // 短token 有效，仍使用原 短token（后续仍需要返回 短token，保证 短token 的一致性）
                this.token = token;
            } else {
                this.token = jwtUtil.generateShortToken(sysUser);
                longToken = jwtUtil.generateLongToken(sysUser);
            }
            // 返回登录用户信息 和 短token
            return R.ok(sysUser).put("token", this.token);
        } else {
            // 不是 当前登录用户 则返回错误信息（因为一般都是 token 过期，而不是 id 不符，所以这个放在最后）
            return R.fail("返回的 token 中的用户 id 与登录用户 id 不符，请重新登录！");
        }
    }

    /**
     * 退出登录，销毁 session
     * @param session
     * @return
     */
    @GetMapping("/logout")
    public R logout(HttpSession session){
        // 直接销毁 session，不再只是消除 用户信息
        session.invalidate();
        return R.ok("退出成功！");
    }

    /**
     * 查询所有用户（不包括超级管理员的信息，超级管理员查询所有管理员）
     *  默认 userName 无参数 查全部，有参数 进行模糊查询
     *  返回分页后的用户信息
     * @param sysUser
     * @return
     */
    @PostMapping("/findAllUser")
    public R findAllUser(@RequestBody SysUser sysUser) {
        log.debug("传递的参数 -> {}", sysUser);
        return R.ok(sysUserService.findAllUser(sysUser));
    }

    /**
     * 添加用户，固定权限等级为 1 管理员（超级管理员添加管理员）
     * @param sysUser
     * @return
     */
    @PostMapping("/addUser")
    public R addUser(@RequestBody SysUser sysUser, HttpSession session) {
        log.debug("传递的参数 -> {}", sysUser);
        SysUser sessionUser = (SysUser) session.getAttribute("sysUser");
        // 判断是否为超级管理员
        if (sessionUser.getUserPermission() != 0) {
            return R.fail("权限不足，无法添加！");
        }
        // 判断 用户名、密码 是否为空
        if (sysUser.getUserName() == null || sysUser.getUserName().equals("")
                || sysUser.getUserPassword() == null || sysUser.getUserPassword().equals("")) {
            return R.fail("用户名或密码不能为空！");
        }
        // 添加用户前 根据用户名 判断 用户是否已存在
        if (sysUserService.findUserByName(sysUser.getUserName()) != null) {
            return R.fail("该用户名已存在！");
        }
        // 设置 创建者、创建时间、更新者、更新时间
        setCreateInfo(sysUser, sessionUser);
        // 执行并返回结果
        return sysUserService.addUser(sysUser) ? R.ok("用户添加成功！") : R.fail("用户添加失败！");
    }

    /**
     * 添加超级管理员
     * @param sysUser
     * @param session
     * @return
     */
    @PostMapping("/addSuperAdmin")
    public R addSuperAdmin(@RequestBody SysUser sysUser, HttpSession session) {
        SysUser sessionUser = (SysUser) session.getAttribute("sysUser");
        // 判断是否为超级管理员
        if (sessionUser.getUserPermission() != 0) {
            return R.fail("权限不足，无法添加！");
        }
        // 判断 用户名、密码 是否为空
        if (sysUser.getUserName() == null || sysUser.getUserName().equals("")
                || sysUser.getUserPassword() == null || sysUser.getUserPassword().equals("")) {
            return R.fail("用户名或密码不能为空！");
        }
        // 添加用户前 根据用户名 判断 用户是否已存在
        if (sysUserService.findUserByName(sysUser.getUserName()) != null) {
            return R.fail("该用户名已存在！");
        }
        // 设置 创建者、创建时间、更新者、更新时间
        setCreateInfo(sysUser, sessionUser);
        // 执行并返回结果
        return sysUserService.addSuperAdmin(sysUser) ? R.ok("用户添加成功！") : R.fail("用户添加失败！");
    }

    /**
     * 修改用户信息，不修改密码，无法修改权限
     * @param sysUser
     * @param session
     * @return
     */
    @PutMapping("/updateUserInfo")
    public R updateUserInfo(@RequestBody SysUser sysUser, HttpSession session) {
        // 设置更新者、更新时间
        sysUser.setUpdateBy(((SysUser) session.getAttribute("sysUser")).getUserName());
        sysUser.setUpdateTime(new Date());
        // 执行并返回结果
        return sysUserService.updateUserInfo(sysUser) ? R.ok("用户信息修改成功！") : R.fail("用户信息修改失败！");
    }

    /**
     * 修改用户密码（修改自己账号密码、超级管理员修改管理员账号密码）
     * @param sysUser
     * @param newPassword
     * @param session
     * @return
     */
    @PutMapping("/updateUserPassword")
    public R updateUserPassword(@RequestBody SysUser sysUser, @RequestParam String newPassword, HttpSession session) {
        String oldPassword = sysUser.getUserPassword();
        if (oldPassword == null || oldPassword.equals("") || newPassword == null || newPassword.equals("")) {
            return R.fail("密码不能为空！");
        } else {
            return sysUserService.updateUserPassword(sysUser, newPassword, session);
        }
    }

    /**
     * 修改用户账号状态（0 停用，1 启用）
     * @param sysUser
     * @param session
     * @return
     */
    @PutMapping("/updateUserState")
    public R updateUserState(@RequestBody SysUser sysUser, HttpSession session) {
        if (((SysUser) session.getAttribute("sysUser")).getUserPermission() != 0)
            return R.fail("权限不足，无法修改！");
        return sysUserService.updateUserState(sysUser) ? R.ok("账号状态修改成功！") : R.fail("账号状态修改失败！");
    }

    /**
     * 删除单个用户（超级管理员 删除 管理员）
     * @param userId
     * @param session
     * @return
     */
    @DeleteMapping("/deleteUser")
    public R deleteUser(@RequestParam int userId, HttpSession session) {
        return (((SysUser) session.getAttribute("sysUser")).getUserPermission() == 1
                && sysUserService.deleteUser(userId))
                ? R.ok("用户删除成功！") : R.fail("用户删除失败！");
    }

    /**
     * 添加账号时，设置 创建者、创建时间、更新者、更新时间
     * @param sysUser
     * @param sessionUser
     */
    private void setCreateInfo(SysUser sysUser, SysUser sessionUser) {
        sysUser.setCreateBy(sessionUser.getUserName());
        sysUser.setCreateTime(new Date());
        sysUser.setUpdateBy(sysUser.getCreateBy());
        sysUser.setUpdateTime(sysUser.getCreateTime());
    }
}
